package utils;

import cn.lg.soar.common.model.LogDTO;
import cn.lg.soar.common.util.reflect.ReflectUtil;
import cn.lg.soar.system.api.model.UserCreateDTO;
import cn.lg.soar.system.biz.modules.auth.entity.User;
import cn.lg.soar.system.biz.modules.monitor.entity.OperationLog;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 属性拷贝生成类
 * @author luguoxiang 469599794@qq.com
 * @Date: 2024/8/23 17:22
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class BeanCopyCodeGenerator {

    /**
     * 生成属性拷贝代码
     * @param thisClass 源数据类
     * @param targetClass 目标数据类
     * @return
     */
    public static String genForThis(Class<?> thisClass, Class<?> targetClass) {
        StringBuilder sb = new StringBuilder();

        Set<String> set = Arrays.stream(thisClass.getDeclaredFields()).map(Field::getName).collect(Collectors.toSet());
        String targetName = targetClass.getSimpleName();
        Set<String> targetFieldNames = getFieldNames(targetClass);
        sb.append("        ").append(targetName).append(" target = new ").append(targetName).append("();\n\n");
        ReflectUtil.scanAllField(thisClass, field -> {
            String fieldName = field.getName();
            if (targetFieldNames.contains(fieldName)) {
                String upperCaseField = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
                sb.append("        target.set").append(upperCaseField);
                if (set.contains(fieldName)) {
                    sb.append("(this.").append(fieldName).append(");\n");
                } else {
                    sb.append("(this.get").append(upperCaseField).append("());\n");
                }
            }
        });
        sb.append("        return target;\n");
        return sb.toString();
    }

    /**
     * 生成属性拷贝代码
     * @param sourceClass
     * @param thisClass
     * @return
     */
    public static String genToThis(Class<?> sourceClass, Class<?> thisClass) {
        StringBuilder sb = new StringBuilder();
        Set<String> set = Arrays.stream(thisClass.getDeclaredFields()).map(Field::getName).collect(Collectors.toSet());
        Set<String> targetFieldNames = getFieldNames(thisClass);
        ReflectUtil.scanAllField(sourceClass, field -> {
            String fieldName = field.getName();
            if (targetFieldNames.contains(fieldName)) {
                String upperCaseField = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
                if (set.contains(fieldName)) {
                    sb.append("        this.").append(fieldName)
                            .append(" = source.get").append(upperCaseField).append("();\n");
                } else {
                    sb.append("        this.set").append(upperCaseField)
                            .append("(source.get").append(upperCaseField).append("());\n");
                }
            }
        });
        return sb.toString();
    }

    public static String genThisCode(Class<?> thisClass, Class<?> targetClass) {
        return genToThis(targetClass, thisClass) +
                "\n\n\n" +
                genForThis(thisClass, targetClass);
    }

    /**
     * 生成属性拷贝代码
     * @param sourceClass 源数据类
     * @param targetClass 目标数据类
     * @return
     */
    public static String generateCode(Class<?> sourceClass, Class<?> targetClass) {
        StringBuilder sb = new StringBuilder();

        String targetName = targetClass.getSimpleName();
        Set<String> targetFieldNames = getFieldNames(targetClass);
        sb.append("        ").append(targetName).append(" target = new ").append(targetName).append("();\n\n");
        ReflectUtil.scanAllField(sourceClass, field -> {
            String fieldName = field.getName();
            if (targetFieldNames.contains(fieldName)) {
                String upperCaseField = Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1);
                sb.append("        target.set").append(upperCaseField)
                        .append("(source.get").append(upperCaseField).append("());\n");
            }
        });
        return sb.toString();
    }

    /**
     * 生成属性拷贝方法
     * @param methodName 方法名称
     * @param sourceClass 源数据类
     * @param targetClass 目标数据类
     * @return
     */
    public static String generateCopyMethod(String methodName, Class<?> sourceClass, Class<?> targetClass) {
        StringBuilder sb = new StringBuilder();

        String sourceName = sourceClass.getSimpleName();
        String targetName = targetClass.getSimpleName();

        sb.append("    public static ").append(targetName).append(" ").append(methodName).append("(").append(sourceName).append(" source) {\n");
        sb.append("        if (source == null) {\n");
        sb.append("         return null;\n");
        sb.append("        }\n\n");
        sb.append(generateCode(sourceClass, targetClass));
        sb.append("\n        return target;\n");
        sb.append("    }\n");

        return sb.toString();
    }

    /**
     * 生成属性拷贝类（会生成两个属性拷贝方法）
     * @param className 生成的类名称
     * @param classA 要拷贝的类型
     * @param classB 要拷贝的类型
     * @return
     */
    public static String generateCopyClass(String className, Class<?> classA, Class<?> classB) {
        String aName = classA.getSimpleName();
        String bName = classB.getSimpleName();

        StringBuilder sb = new StringBuilder();
        sb.append("public class ").append(className).append(" {\n\n");
        sb.append(generateCopyMethod("to" + bName, classA, classB));
        sb.append(generateCopyMethod("to" + aName, classB, classA));
        sb.append("}\n");
        return sb.toString();
    }

    private static Set<String> getFieldNames(Class<?> clazz) {
        Set<String> fieldNames = new HashSet<>();
        ReflectUtil.scanAllField(clazz, field -> {
            fieldNames.add(field.getName());
        });
        return fieldNames;
    }

    public static void main(String[] args) {
        String s;
        s = BeanCopyCodeGenerator.generateCopyClass("SSs", LogDTO.class, OperationLog.class);
//        s = genThisCode(TemporaryPasswordVo.class, TemporaryPassword.class);
        System.out.println(s);
    }

}